package cas.ihep.pwa.evtgen;
import java.io.Serializable;
import java.util.ArrayList;

public class EvtAbsLineShape implements Serializable{

    protected ArrayList<EvtId> _userSetPWD1=new ArrayList<>(),_userSetPWD2=new ArrayList<>();
    protected ArrayList<Integer> _userSetPW=new ArrayList<>();
    protected double _mass;
    protected double _massMin;
    protected double _massMax;
    protected double _width;
    protected double _maxRange;
    protected double _2ndmass;  //pingrg,2010-9-24; for interference particle
    protected double _2ndwidth;
    protected double _blatt;
    protected EvtSpinType.SpinType _spin;
    protected boolean _includeDecayFact;
    protected boolean _includeBirthFact;
    protected boolean _fixMassForMax;

    public void reSet2ndMass(double mass) { _2ndmass=mass;}
    public void reSet2ndWidth(double width) { _2ndwidth=width;}
    public void reSetMassMin(double mass) { _massMin=mass;}
    public void reSetMassMax(double mass) { _massMax=mass;}
    public void reSetBlatt(double b) {_blatt=b;}
    public void includeBirthFactor(boolean yesno) { _includeBirthFact = yesno; }
    public void includeDecayFactor(boolean yesno) { _includeDecayFact = yesno; }

    public void setPWForDecay( int spin, EvtId d1, EvtId d2) {
        _userSetPW.add(spin);
        _userSetPWD1.add(d1);
        _userSetPWD2.add(d2);
    }

    public double getRandMass(EvtId parId[], int nDaug, EvtId dauId[], EvtId othDaugId[],double maxMass, double []dauMasses) {
        if ( _width< 0.0001) return _mass;
        double mMin=_massMin;
        double mMax=_massMax;
        if ( maxMass>-0.5 && maxMass< mMax) mMax=maxMass;
        double ymin = Math.atan( 2.0*(mMin-_mass)/_width);
        double ymax = Math.atan( 2.0*(mMax-_mass)/_width);
        double genmass,maxratio=0,ratioloc=0,rndm=0;
        boolean flag;
        boolean first = true;
        do {
            genmass = (_mass + ((_width / 2.0) * Math.tan(EvtRandom.flat(ymin, ymax))));
            if ((flag=_2ndmass > 0.00001 && _2ndwidth > 0.00001)) {
                if (first) {
                    for (int i = 0; i < 5000; i++) {
                        double maxloc = NRBWratio(EvtRandom.flat(mMin, mMax));
                        if (maxloc > maxratio) {
                            maxratio = maxloc;
                        }
                    }
                    first = false;
                    maxratio = 1.2 * maxratio;
                }
                ratioloc = NRBWratio(genmass) / maxratio;
                rndm = EvtRandom.flat();
            }
        }while(flag && rndm>ratioloc);
        return genmass;
    }
    public double getMassProb(double mass, double massPar, int nDaug, double massDau[]) {
        double dTotMass=0.;
        if ( nDaug>1) {
            int i;
            for (i=0; i<nDaug; i++) {
                dTotMass+=massDau[i];
            }
            if ( (mass<dTotMass) ) return 0.;
        }
        if ( _width< 0.0001) return 1.;

        if ( massPar>0.0000000001 ) {
            if ( mass > massPar) return 0.;
        }
        return 1.0;
    }

    public void fixForSP6() { _fixMassForMax=true;}

    public double getMass() {return _mass;}
    public double getMassMin() {return _massMin;}
    public double getMassMax() {return _massMax;}
    public double getMaxRange() {return _maxRange;}
    public double getWidth() {return _width;}
    public double get2ndMass(){return _2ndmass;}
    public double get2ndWidth(){return _2ndwidth;}
    public EvtSpinType.SpinType getSpinType() {return _spin;}
    public double rollMass(){
        double ymin, ymax;
        double temp;
        if ( _width < 0.0001 ) {
            return _mass;
        }else{
            ymin = Math.atan( 2.0*(_massMin-_mass)/_width);
            ymax = Math.atan( 2.0*(_massMax-_mass)/_width);
            temp= ( _mass + ((_width/2.0)*Math.tan(EvtRandom.flat(ymin,ymax))));
            return temp;
        }
    }
    public double NRBWratio(double mass){
        double pi=3.1415926;
        double bw1= _width   /2/pi/((_mass-mass)*(_mass-mass)+_width*_width/4);
        double bw2= _2ndwidth/2/pi/((_2ndmass-mass)*(_2ndmass-mass)+_2ndwidth*_2ndwidth/4);
        double ratio;
        if(bw1 !=0 ){
            ratio=Math.sqrt(bw2/bw1);
        }else{
            throw new RuntimeException("First Breit-Wigner is 0");
        }
        return ratio;
    }
    public void reSetMass(double mass) { _mass=mass;}
    public void reSetWidth(double width) {
        _width=width;
        double maxdelta=15.0*width;
        if ( _maxRange > 0.00001 ) {
            _massMax=_mass+maxdelta;
            _massMin=_mass-_maxRange;
        }else{
            _massMax=_mass+maxdelta;
            _massMin=_mass-15.0*width;
        }
        if ( _massMin< 0. ) _massMin=0.;
        _massMax=_mass+maxdelta;
    }

    public EvtAbsLineShape(){}

    public EvtAbsLineShape(double mass,double width,double maxRange,EvtSpinType.SpinType sp){
        _includeDecayFact = true;
        _includeBirthFact = true;
        _fixMassForMax =true;
        _mass=mass;
        _width=width;
        _spin=sp;
        _blatt=3.0;
        _maxRange=maxRange;
        double maxdelta=15.0*width;
        //if ( width>0.001 ) {
        //  if ( 5.0*width < 0.6 ) maxdelta = 0.6;
        //}
        if ( maxRange > 0.00001 ) {
            _massMax=mass+maxdelta;
            _massMin=mass-maxRange;
        }
        else{
            _massMax=mass+maxdelta;
            _massMin=mass-15.0*width;
        }
        if ( _massMin< 0. ) _massMin=0.;
        _massMax=mass+maxdelta;
    }

    public EvtAbsLineShape(EvtAbsLineShape x){
        _includeDecayFact = x._includeDecayFact;
        _includeBirthFact = x._includeBirthFact;
        _mass=x._mass;
        _massMax=x._massMax;
        _massMin=x._massMin;
        _width=x._width;
        _maxRange=x._maxRange;
        _fixMassForMax = x._fixMassForMax;
    }

    public EvtAbsLineShape duplicate(){
        return new EvtAbsLineShape(this);
    }
}

